package com.ttxs.generator;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.ttxs.generator.engine.CustomFreemarker;
import com.ttxs.generator.util.Constants;
import com.ttxs.generator.util.DirectoryUtils;
import com.ttxs.generator.util.PathUtils;
import com.ttxs.generator.vo.FormBean;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

import static com.ttxs.generator.util.Constants.BEGIN_PORT;

@RestController
@Slf4j
public class CodeController {
    @Autowired
    private CustomFreemarker customFreemarker;

    public CodeController() {
        File rootPath = new File(FormBean.ROOT_PATH);
        if(!rootPath.exists()) {
            rootPath.mkdir();
        }
        log.info("代码存储目录：{}", rootPath.getAbsolutePath());
    }

    @InitBinder("formBean")
    public void setFromBeanPrefix(WebDataBinder webDataBinder) {
        webDataBinder.setFieldDefaultPrefix("formBean.");
    }
    // 处理 all 情况
    protected static List<String> getTables(String tables) {
        return StringUtils.isEmpty(tables) ? Collections.emptyList() : Arrays.asList(tables.split(","));
    }

    @RequestMapping("/generate")
    public String index(FormBean formBean) throws CloneNotSupportedException, IOException {
        formBean.setSpringCloudPackageName(formBean.getPackageName());
        String dbNames = formBean.getDbNames();
        //替换中文逗号
        dbNames = dbNames.replace("，", ",");
        List<String> dbNameList = Arrays.asList(dbNames.split(","));
        // 存储artifactId
        formBean.setArtifactIdList(dbNameList.stream().map(this::formatArtifactId).collect(Collectors.toList()));
        // 设置项目类型
        formBean.setJavaProjectType(dbNameList.size() == 1 ? Constants.SPRING_BOOT : Constants.SPRING_CLOUD);
        /**
         * 生成前后端代码
         * 单个数据库生成springBoot项目
         * 多个数据库生成springCloud项目
         */
        int beginPort = BEGIN_PORT;
        for (String dbName : dbNameList) {
            FormBean clonedForm = (FormBean) formBean.clone();
            clonedForm.setUrl("jdbc:mysql://localhost:3306/" + dbName);
            // 设置artifactId
            clonedForm.setArtifactId(formatArtifactId(dbName));
            // 存储端口号
            clonedForm.setPort(String.valueOf(beginPort++));
            // 后端项目存储路径
            clonedForm.setJavaProjectPath(FormBean.ROOT_PATH + File.separator + clonedForm.getArtifactId());
            // 前端页面存储路径
            clonedForm.setVueProjectPath(FormBean.ROOT_PATH + File.separator + clonedForm.getArtifactId()
                    + File.separator + clonedForm.getArtifactId() + "-ui");
            // springCloud项目特殊设置
            if (clonedForm.isSpringCloud()) {
                set4SpringCloud(clonedForm);
            } else {
                // springBoot项目platformName和artifactId相同
                clonedForm.setPlatformName(clonedForm.getArtifactId());
            }
            // 指定前端页面模板路径
            clonedForm.setTtxsUiVuePath(CodeController.class.getClassLoader().getResource("ttxs-ui-vue").getPath());
            // 生成所有表
            clonedForm.setTableNames("");
            // 清空模块名
            clonedForm.setModuleName("");

            FastAutoGenerator.create(clonedForm.getUrl(), clonedForm.getDbUsername(), clonedForm.getDbPassword())
                    .injectionConfig(builder -> {
                        /**
                         * 自定义模板文件
                         * 调用mybatis plus代码生成器，自动根据表名字生成页面和JS
                         * 存储在customFile中的条目会根据表名循环生成
                         */
                        Map<String, String> customFile = new HashMap<>();
                        customFile.put("index.vue", "templates/index.vue.ftl");
                        customFile.put("index.js", "templates/index.js.ftl");
                        builder.customFile(customFile);
                        // 自定义模板变量
                        Map<String, Object> customMap = new HashMap<>();
                        customMap.put(Constants.FORM_BEAN, clonedForm);
                        builder.customMap(customMap);
                    })
                    .globalConfig(builder -> {
                        builder.author(clonedForm.getAuthor()) // 设置作者
                                .fileOverride() // 覆盖已生成文件
                                .outputDir(PathUtils.get(PathUtils.Java.srcMainJava, clonedForm.getJavaProjectPath())); // 指定输出目录
                        if (clonedForm.isSwagger()) {
                            builder.enableSwagger(); // 开启 swagger 模式
                        }
                    })
                    .packageConfig(builder -> {
                        builder.parent(clonedForm.getPackageName()) // 设置父包名
                                .moduleName(clonedForm.getModuleName()) // 设置父包模块名
                                .pathInfo(Collections.singletonMap(OutputFile.mapperXml, PathUtils.get(PathUtils.Java.mapperXml, clonedForm.getJavaProjectPath()))); // 设置mapperXml生成路径
                    })
                    .strategyConfig(builder -> {
                        builder.addInclude(getTables(clonedForm.getTableNames())); // 设置需要生成的表名
                        if (org.springframework.util.StringUtils.hasText(clonedForm.getTablePrefixes())) {
                            builder.addTablePrefix(clonedForm.getTablePrefixes().split(",")); // 设置过滤表前缀
                        }
                        builder.controllerBuilder().enableRestStyle();
                    })
                    .templateEngine(customFreemarker) // 使用Freemarker引擎模板，默认的是Velocity引擎模板
                    .execute();
        }
        // 创建gateway工程
        if (formBean.isStaticRoute() && formBean.isSpringCloud()) {
            String source = CodeController.class.getClassLoader().getResource("api-gateway").getPath();
            String target = FormBean.ROOT_PATH + File.separator + formBean.getPlatformName() + File.separator + "api-gateway";
            DirectoryUtils.copyDirectory(source, target, "target");
        }
        return "恭喜您成功生成代码，祝您工作顺利，学习进步";
    }

    /**
     * 下划线转中划线
     * 驼峰转中划线
     * 转小写
     * artifactId命名规范：小写，单词使用中划线连接
     * @param dbName
     * @return
     */
    private String formatArtifactId(String dbName) {
        // 下划线转中划线
        dbName = dbName.replace("_", "-");
        // 驼峰转中划线
        dbName = StringUtils.camelToHyphen(dbName);
        // 转小写
        return dbName.toLowerCase();
    }

    /**
     * 中划线转下划线
     * 下划线转驼峰
     * 转小写
     * @param input
     * @return
     */
    private String formatPackageName(String input) {
        // 中划线转下划线
        input = input.replace("-", "_");
        // 下划线转驼峰
        input = StringUtils.underlineToCamel(input);
        // 转小写
        return input.toLowerCase();
    }

    private void set4SpringCloud(FormBean formBean) {
        // 后端项目存储路径
        formBean.setJavaProjectPath(FormBean.ROOT_PATH + File.separator
                + formBean.getPlatformName() + File.separator
                + formBean.getArtifactId());
        // 前端页面存储路径
        formBean.setVueProjectPath(FormBean.ROOT_PATH + File.separator
                + formBean.getPlatformName() + File.separator
                + formBean.getPlatformName() + "-ui");
        // 包名字
        formBean.setPackageName(formBean.getPackageName() + "." + formatPackageName(formBean.getArtifactId()));
    }

    @ExceptionHandler
    public String handler(Throwable ex) {
        log.error(ex.getMessage(), ex);
        return ex.getMessage();
    }

}
